/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2021-2021.
 * Description: support net hooks register
 * Author: douzhaolei
 * Create: 2021-11-15
 */
#include <net/net_hook_register.h>

#define DECLEAR_NET_FUN(hook_enum, fun) \
{ \
	.type = hook_enum, \
	.p_hook_fun = (void **)(&fun), \
}

int (*g_dad_check_hook)(struct net_device *dev,
	const struct in6_addr *solicit,
	const struct in6_addr *saddr);
EXPORT_SYMBOL(g_dad_check_hook);

int (*g_rps_check_cpu)(int cpu);

#if IS_ENABLED(CONFIG_NETFILTER)
void (*g_pv_save_port_range)(const struct sk_buff *skb,
	struct xt_action_param *par);

void (*pf_ip_nf_flow_log_hook)(struct sk_buff *pskb,
	struct nf_hook_state *state,
	unsigned int verdict,
	const struct nf_hook_entries *e,
	unsigned int s);
#endif

void (*g_route_query_err)(int stage, unsigned short family,
	struct sk_buff *skb, void *flow);
EXPORT_SYMBOL(g_route_query_err);

void (*g_pv_rtv4_process)(int event, __be32 key,
	int dst_len, u32 tb_id,
	u8 fa_type, struct fib_info *fa_info);

void (*g_pv_set_neighbour_privateinfo)(struct sk_buff *skb,
	struct neighbour *neigh);
EXPORT_SYMBOL(g_pv_set_neighbour_privateinfo);

void (*g_pv_set_socket_l2info)(struct sk_buff *skb,
	struct sock *sk,
	struct iov_iter *msg_iter,
	unsigned int len,
	unsigned int *setlen) __read_mostly;
EXPORT_SYMBOL(g_pv_set_socket_l2info);

#if IS_ENABLED(CONFIG_NETFILTER)
unsigned int (*nf_conntrack_confirm_ipv6_hook)(
	struct sk_buff *skb,
	const struct nf_hook_state *state,
	int conntrack_ret);
EXPORT_SYMBOL(nf_conntrack_confirm_ipv6_hook);
#endif

#if IS_ENABLED(CONFIG_IPV6)
void (*g_pv_rt_process)(int event, struct fib6_info *rt);
EXPORT_SYMBOL(g_pv_rt_process);

int (*g_should_ignore_linklocal)(struct net_device *dev);
EXPORT_SYMBOL(g_should_ignore_linklocal);

int (*p_udp6_lib_ucast_deliver)(struct sock *sk, struct net *net,
	struct sk_buff *skb,
	struct udphdr  *uh,
	struct in6_addr *saddr,
	struct in6_addr *daddr,
	struct udp_table *udptable);
EXPORT_SYMBOL(p_udp6_lib_ucast_deliver);
#endif

int (*g_pv_nbgethit_process)(struct neighbour *neigh);

void (*nb_event_hook)(struct neighbour *neigh);

int (*g_pv_fw_ing)(struct sk_buff *skb);

int (*g_pv_fw_egr)(struct sk_buff *skb);

int (*hw_localout_ip_send_hook)(struct sk_buff *skb);

#if IS_ENABLED(CONFIG_IPV6)
int (*ip6_hw_localout_ip_send_hook)(struct sk_buff *skb);
EXPORT_SYMBOL(ip6_hw_localout_ip_send_hook);

int (*ipv6_raw_socket_filter_hook)(struct sk_buff *skb, int nexthdr);
EXPORT_SYMBOL(ipv6_raw_socket_filter_hook);
#endif

void (*skb_priv_copy)(struct sk_buff *new, const struct sk_buff *old);
EXPORT_SYMBOL(skb_priv_copy);

int (*wifipktfree)(struct sk_buff *skb);
EXPORT_SYMBOL(wifipktfree);

#ifdef CONFIG_RTOS_NET_WIFIPKT
int (*wifipktfreedata)(struct sk_buff *skb);
#endif

void (*wifipktadd)(struct sk_buff *skb);
EXPORT_SYMBOL(wifipktadd);

int (*ffwd_ipsec_rcv_hook)(struct sk_buff *skb);

int (*ipsec_sendout_hook)(struct sk_buff *skb);

int (*ipv4_raw_socket_filter_hook)(struct sk_buff *skb, const struct iphdr *iph, int hash);

int (*igmpv3_sendpack_hook)(struct sk_buff *skb);

int (*igmp_send_report_hook)(struct sk_buff *skb);

const static struct net_hook_fun array_net_hook_fun[NET_HOOK_MAX] = {
	DECLEAR_NET_FUN(NET_HOOK_G_DAD_CHECK_HOOK, g_dad_check_hook),
	DECLEAR_NET_FUN(NET_HOOK_G_RPS_CHECK_CPU, g_rps_check_cpu),
#if IS_ENABLED(CONFIG_NETFILTER)
	DECLEAR_NET_FUN(NET_HOOK_PV_SAVE_PORT_RANGE, g_pv_save_port_range),
	DECLEAR_NET_FUN(NET_HOOK_PF_IP_NF_FLOW_LOG_HOOK, pf_ip_nf_flow_log_hook),
#endif
	DECLEAR_NET_FUN(NET_HOOK_G_ROUTE_QUERY_ERR, g_route_query_err),
	DECLEAR_NET_FUN(NET_HOOK_G_PV_RTV4_PROCESS, g_pv_rtv4_process),
	DECLEAR_NET_FUN(NET_HOOK_G_PV_SET_NEIGHBOUR_PRIVATEINFO,
		g_pv_set_neighbour_privateinfo),
	DECLEAR_NET_FUN(NET_HOOK_G_PV_SET_SOCKET_L2INFO, g_pv_set_socket_l2info),
#if IS_ENABLED(CONFIG_NETFILTER)
	DECLEAR_NET_FUN(NET_HOOK_NF_CONNTRACK_CONFIRM_IPV6_HOOK,
		nf_conntrack_confirm_ipv6_hook),
#endif
#if IS_ENABLED(CONFIG_IPV6)
	DECLEAR_NET_FUN(NET_HOOK_G_PV_RT_PROCESS, g_pv_rt_process),
	DECLEAR_NET_FUN(NET_HOOK_G_SHOULD_IGNORE_LINKLOCAL,
		g_should_ignore_linklocal),
	DECLEAR_NET_FUN(NET_HOOK_P_UDP6_LIB_UCAST_DELIVER,
		p_udp6_lib_ucast_deliver),
#endif
	DECLEAR_NET_FUN(NET_HOOK_G_PV_NBGETHIT_PROCESS, g_pv_nbgethit_process),
	DECLEAR_NET_FUN(NET_HOOK_NB_EVENT_HOOK, nb_event_hook),
	DECLEAR_NET_FUN(NET_HOOK_G_PV_FW_ING, g_pv_fw_ing),
	DECLEAR_NET_FUN(NET_HOOK_G_PV_FW_EGR, g_pv_fw_egr),
	DECLEAR_NET_FUN(NET_HOOK_HW_LOCALOUT_IP_SEND_HOOK,
		hw_localout_ip_send_hook),
#if IS_ENABLED(CONFIG_IPV6)
	DECLEAR_NET_FUN(NET_HOOK_IP6_HW_LOCALOUT_IP_SEND_HOOK,
		ip6_hw_localout_ip_send_hook),
#endif
	DECLEAR_NET_FUN(NET_HOOK_SKB_PRIV_COPY, skb_priv_copy),
	DECLEAR_NET_FUN(NET_HOOK_WIFIPKTFREE, wifipktfree),
	DECLEAR_NET_FUN(NET_HOOK_WIFIPKTADD, wifipktadd),
	DECLEAR_NET_FUN(NET_HOOK_FFWD_IPSEC_RCV, ffwd_ipsec_rcv_hook),
	DECLEAR_NET_FUN(NET_HOOK_IPSEC_SENDOUT, ipsec_sendout_hook),
	DECLEAR_NET_FUN(NET_HOOK_RAW_SOCKET_FILTER, ipv4_raw_socket_filter_hook),
#if IS_ENABLED(CONFIG_IPV6)
	DECLEAR_NET_FUN(NET_HOOK_IPV6_RAW_SOCKET_FILTER,
		ipv6_raw_socket_filter_hook),
#endif
	DECLEAR_NET_FUN(NET_HOOK_IGMPV3_SENDPACK_HOOK, igmpv3_sendpack_hook),
	DECLEAR_NET_FUN(NET_HOOK_IGMP_SEND_REPORT_HOOK, igmp_send_report_hook),
#ifdef CONFIG_RTOS_NET_WIFIPKT
	DECLEAR_NET_FUN(NET_HOOK_WIFIPKTFREEDATA, wifipktfreedata),
#endif
};

/* this function do not support concurrent scene, make use of some lock if necessary */
int rtos_net_hook(enum NET_HOOK_ACTION action, enum NET_HOOK_FUN fun_type, void *p_net_hook_fun)
{
	if ((fun_type < 0) || (fun_type >= NET_HOOK_MAX))
		return -EINVAL;
	if (array_net_hook_fun[fun_type].type != fun_type)
		return -EINVAL;
	if (action == NET_HOOK_ACTION_REGISTER)
		*(array_net_hook_fun[fun_type].p_hook_fun) = p_net_hook_fun;
	else if (action == NET_HOOK_ACTION_UNREGISTER)
		*(array_net_hook_fun[fun_type].p_hook_fun) = NULL;
	return 0;
}
EXPORT_SYMBOL_NS(rtos_net_hook, HW_RTOS_NS);

/* this function do not support concurrent scene, make use of some lock if necessary */
void *rtos_net_hook_get(enum NET_HOOK_FUN fun_type)
{
	if ((fun_type < 0) || (fun_type >= NET_HOOK_MAX))
		return ERR_PTR(-EINVAL);
	if (array_net_hook_fun[fun_type].type != fun_type)
		return ERR_PTR(-EINVAL);
	return *(array_net_hook_fun[fun_type].p_hook_fun);
}
EXPORT_SYMBOL_NS(rtos_net_hook_get, HW_RTOS_NS);
